home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------------------
-
- unzip.c
-
- UnZip - a zipfile extraction utility. See below for make instructions, or
- read the comments in Makefile and the various Contents files for more de-
- tailed explanations. To report a bug, send a *complete* description to
- zip-bugs@cs.ucla.edu; include machine type, operating system and version,
- compiler and version, and reasonably detailed error messages or problem
- report. To join Info-ZIP, send a message to izip-mgr@wkuvx1.bitnet (or
- izip-mgr%wkuvx1.bitnet@ukcc.uky.edu).
-
- UnZip 5.x is a greatly expanded and partially rewritten successor to 4.x,
- which in turn was almost a complete rewrite of version 3.x. For a detailed
- revision history, see UnzpHist.zip at quest.jpl.nasa.gov. For a list of
- the many (near infinite) contributors, see "CONTRIBS" in the UnZip source
- distribution.
-
- ---------------------------------------------------------------------------
-
- To compile (partial instructions):
-
- under Unix (cc): make <system name>
- (type "make list" for a list of valid names, or read Makefile for
- details. "make unzip" works for most systems. If you have a NEW
- system, not covered by any of the existing targets, send FULL infor-
- mation--hardware, OS, versions, etc.--to zip-bugs@cs.ucla.edu)
-
- under VMS (VAX C or GNU C): @make_vaxc_unzip or @make_gcc_unzip
- (from VMS sub-archive; can also use MMS or MAKE/VMS; see VMS.notes)
-
- under OS/2 (MSC, gcc, IBM C Set/2, Watcom C): make -f makefile.os2
- (from OS2 sub-archive; for MSC, use NMAKE)
-
- under MS-DOS (MSC, Turbo C, or Borland C++): use the makefiles or
- project files in the MSDOS sub-archive; edit or otherwise modify
- as appropriate. For MSC, use NMAKE.
-
- under MS Windows 3.1: get wunz13sr.{zip | zoo | whatever} and use
- the included makefile
-
- under Windows NT: use makefile.nt (from NT sub-archive)
-
- under Macintosh OS: double click on unzip.make; press <Command>-M
- (from MAC sub-archive)
-
- under AmigaDOS: lmk -f amiga/LMKFile all (from AMIGA sub-archive;
- see also MakeScript)
-
- under TOPS-20: use make.mic and "do make"
-
- under Atari TOS: needs considerable work yet...
-
- ---------------------------------------------------------------------------
-
- Version: unzip51.{tar.Z | zip | zoo} for Unix, VMS, OS/2, MS-DOS, Windows,
- Windows NT, Macintosh, Amiga and TOPS-20. Decryption requires
- sources in zcrypt20.zip, and Windows (not NT) support requires
- sources in wunz13sr.zip. See accompanying file "Where" in the
- main source distribution for ftp, uucp and mail-server sites.
- Copyrights: see accompanying file "COPYING" in UnZip source distribution.
-
- ---------------------------------------------------------------------------*/
-
-
-
-
-
- #include "unzip.h" /* includes, typedefs, macros, etc. */
- #include "crypt.h"
- #ifdef MSWIN
- # include "wizunzip.h"
- #endif
-
- /* #define RELEASE */
- #ifdef RELEASE
- # define VERSION "v5.0 of 21 August 1992" /* official release version */
- #else
- # define VERSION "v5.1d BETA of 22 Oct 92" /* internal beta level */
- #endif
-
-
-
-
-
- /**********************/
- /* Global Variables */
- /**********************/
-
- int aflag=0; /* -a: do ASCII to EBCDIC translation, or CR-LF */
- /* to CR or LF conversion of extracted files */
- /* int bflag=0; RESERVED for -b: extract as binary */
- int cflag=0; /* -c: output to stdout */
- int fflag=0; /* -f: "freshen" (extract only newer files) */
- int jflag=0; /* -j: junk pathnames */
- int overwrite_none=0; /* -n: never overwrite files (no prompting) */
- int overwrite_all=0; /* -o: OK to overwrite files without prompting */
- int force_flag=0; /* (shares -o for now): force to override errors, etc. */
- int quietflg=0; /* -q: produce a lot less output */
- #ifdef DOS_OS2
- int sflag=1; /* -s: allow spaces (blanks) in filenames */
- #endif
- int tflag=0; /* -t: test */
- int uflag=0; /* -u: "update" (extract only newer & brand-new files) */
- static int U_flag=0; /* -U: leave filenames in upper or mixed case */
- static int vflag=0; /* -v: view directory (only used in unzip.c) */
- int V_flag=0; /* -V: don't strip VMS version numbers */
- #ifdef VMS
- int secinf=0; /* -X: keep owner/protection */
- #endif
- int zflag=0; /* -z: display only the archive comment */
-
- int filespecs; /* number of real file specifications to be matched */
- int xfilespecs; /* number of excluded filespecs to be matched */
- int process_all_files = 0;
- longint real_ecrec_offset, expect_ecrec_offset;
-
- longint csize; /* used by list_files(), ReadByte(): must be signed */
- longint ucsize; /* used by list_files(), unReduce(), explode() */
-
- static char *fnames[2] = {"*", NULL}; /* default filenames vector */
- char **pfnames = fnames, **pxnames = &fnames[1];
- char sig[5];
- char answerbuf[10];
-
- min_info info[DIR_BLKSIZ], *pInfo=info;
-
- #ifdef OS2
- int longname; /* used in extract.c, mapname.c and file_io.c */
- char longfilename[FILNAMSIZ];
- #endif
-
- #ifdef CRYPT
- char *key = (char *)NULL; /* password with which to decrypt data, or NULL */
- #endif
-
- /*---------------------------------------------------------------------------
- unShrink/unReduce/explode/inflate working storage and globals:
- ---------------------------------------------------------------------------*/
-
- union work area; /* see unzip.h for the definition of work */
- ulg crc32val;
-
- ush mask_bits[] = {
- 0x0000,
- 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
- };
-
- /*---------------------------------------------------------------------------
- Input file variables:
- ---------------------------------------------------------------------------*/
-
- uch *inbuf, *inptr; /* input buffer (any size is legal) and pointer */
- int incnt;
-
- ulg bitbuf;
- int bits_left;
- boolean zipeof;
-
- #ifdef MSWIN
- char *zipfn;
- #else
- char zipfn[FILNAMSIZ];
- #endif
- int zipfd; /* zipfile file handle */
- longint ziplen;
-
- uch *hold;
- char local_hdr_sig[5] = "\120"; /* remaining signature bytes come later */
- char central_hdr_sig[5] = "\120"; /* (must initialize at runtime so unzip */
- char end_central_sig[5] = "\120"; /* executable won't look like a zipfile) */
- /* char extd_local_sig[5] = "\120"; NOT USED YET */
-
- cdir_file_hdr crec; /* used in unzip.c, extract.c, misc.c */
- local_file_hdr lrec; /* used in unzip.c, extract.c */
- ecdir_rec ecrec; /* used in unzip.c, extract.c */
- struct stat statbuf; /* used by main, mapname, check_for_newer */
-
- longint extra_bytes = 0; /* used in unzip.c, misc.c */
- longint cur_zipfile_bufstart; /* extract_or_test_files, readbuf, ReadByte */
-
- #ifdef MACOS
- short gnVRefNum;
- long glDirID;
- OSType gostCreator;
- OSType gostType;
- boolean fMacZipped;
- boolean macflag;
- CursHandle rghCursor[4]; /* status cursors */
- short giCursor = 0;
- #endif
-
- /*---------------------------------------------------------------------------
- Output stream variables:
- ---------------------------------------------------------------------------*/
-
- uch *outbuf; /* buffer for rle look-back */
- uch *outptr;
- #ifdef MSWIN
- uch __far *outout;
- char *filename;
- #else /* !MSWIN */
- uch *outout; /* scratch pad for ASCII-native trans */
- char filename[FILNAMSIZ];
- #endif /* ?MSWIN */
- uch *extra_field = (uch *)NULL; /* used by VMS, Mac and OS/2 versions */
- longint outpos; /* absolute position in outfile */
- int outcnt; /* current position in outbuf */
- int outfd;
- int mem_mode = 0;
- int disk_full;
- int newfile;
- #ifdef SYMLINKS
- int symlnk;
- #endif
-
- static char unkn[10];
- static ush methnum;
-
- /*---------------------------------------------------------------------------
- unzip.c repeated error messages (we use all of these at least twice)
- ---------------------------------------------------------------------------*/
-
- char *EndSigMsg = "\nwarning:\
- didn't find end-of-central-dir signature at end of central dir.\n";
- char *CentSigMsg =
- "error: expected central file header signature not found (file #%u).\n";
- char *SeekMsg =
- "error: attempt to seek before beginning of zipfile\n%s";
-
- #ifdef VMS
- char *ReportMsg = "\
- (please check that you have transferred or created the zipfile in the\n\
- appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
- #else /* !VMS */
- char *ReportMsg = "\
- (please check that you have transferred or created the zipfile in the\n\
- appropriate BINARY mode and that you have compiled unzip properly)\n";
- #endif /* ?VMS */
-
-
-
-
-
- #ifdef MSWIN
- # include "winsetup.c" /* duplicates some of code in main() */
- #else /* !MSWIN */
-
- /******************/
- /* Main program */
- /******************/
-
- int main(argc, argv) /* return PK-type error code (except under VMS) */
- int argc;
- char *argv[];
- {
- char *s;
- int c, error=FALSE, negative=0;
-
-
- #if defined(MACOS) || defined(MALLOC_WORK)
- area.Slide = (uch *)calloc(8193, sizeof(short)+sizeof(char)+sizeof(char));
- area.shrink.Prefix_of = (short *)area.Slide;
- area.shrink.Suffix_of = area.Slide + (sizeof(short)*(HSIZE+1));
- area.shrink.Stack = area.Slide + (sizeof(short) + sizeof(char))*(HSIZE+1);
- #endif
-
- /*---------------------------------------------------------------------------
- Macintosh initialization code.
- ---------------------------------------------------------------------------*/
-
- #ifdef MACOS
- #ifdef THINK_C
- # include <console.h>
- static char *argstr[30], args[30*64];
- Point p;
- SFTypeList sfT;
- EventRecord theEvent;
- short eMask;
- SFReply fileRep;
- #endif /* THINK_C */
- int a;
-
- for (a = 0; a < 4; ++a)
- rghCursor[a] = GetCursor(a+128);
- giCursor = 0;
-
- #ifdef THINK_C
- for (a = 0; a < 30; ++a)
- argstr[a] = &args[a*64];
- start:
- tflag=vflag=cflag=aflag=jflag=U_flag=quietflg=fflag=uflag=zflag = 0;
- local_hdr_sig[1] = central_hdr_sig[1] = end_central_sig[1] = '\0';
- /* extd_local_sig[1] = '\0'; */
- error = FALSE;
-
- argc = ccommand(&argv);
- SetPt(&p, 40, 40);
-
- SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep);
- if (fileRep.good) {
- macfstest(fileRep.vRefNum);
- ResolveMacVol(fileRep.vRefNum, &gnVRefNum, &glDirID, NULL);
- for (a = 1; a < argc; ++a)
- if (argv[a][0] == '-')
- BlockMove(argv[a], argstr[a], (strlen(argv[a]) > 63) ? 64 :
- strlen(argv[a])+1);
- else
- break;
- PtoCstr((char *)fileRep.fName);
- strcpy(argstr[a], (char *)fileRep.fName);
- for (; a < argc; ++a)
- BlockMove(argv[a], argstr[a+1], (strlen(argv[a]) > 63) ? 64 :
- strlen(argv[a])+1);
- ++argc;
- argv = argstr;
-
- if (hfsflag == FALSE) /* can't support directories: junk pathnames */
- jflag = 1;
- }
- #endif /* THINK_C */
- #endif /* MACOS */
-
- /*---------------------------------------------------------------------------
- Set signal handler for restoring echo, warn of zipfile corruption, etc.
- ---------------------------------------------------------------------------*/
-
- signal(SIGINT, handler);
- #ifdef SIGTERM /* Amiga has no SIGTERM; maybe others */
- signal(SIGTERM, handler);
- #endif
- #ifdef SIGBUS
- signal(SIGBUS, handler);
- #endif
- #ifdef SIGSEGV
- signal(SIGSEGV, handler);
- #endif
-
- /*---------------------------------------------------------------------------
- Debugging info for checking on structure padding:
- ---------------------------------------------------------------------------*/
-
- #ifdef DEBUG_STRUC
- printf("local_file_hdr size: %X\n",
- sizeof(local_file_hdr));
- printf("local_byte_hdr size: %X\n",
- sizeof(local_byte_hdr));
- printf("actual size of local headers: %X\n", LREC_SIZE);
-
- printf("central directory header size: %X\n",
- sizeof(cdir_file_hdr));
- printf("central directory byte header size: %X\n",
- sizeof(cdir_byte_hdr));
- printf("actual size of central dir headers: %X\n", CREC_SIZE);
-
- printf("end central dir record size: %X\n",
- sizeof(ecdir_rec));
- printf("end central dir byte record size: %X\n",
- sizeof(ec_byte_rec));
- printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
- #endif /* DEBUG_STRUC */
-
- /*---------------------------------------------------------------------------
- Put environment-variable options into the queue, then rip through any
- command-line options lurking about...
- ---------------------------------------------------------------------------*/
-
- envargs(&argc, &argv, ENV_UNZIP);
-
- while (--argc > 0 && (*++argv)[0] == '-') {
- s = argv[0] + 1;
- while ((c = *s++) != 0) { /* "!= 0": prevent Turbo C warning */
- switch (c) {
- case ('-'):
- ++negative;
- break;
- case ('a'):
- if (negative)
- aflag = FALSE, negative = 0;
- else
- aflag = TRUE;
- break;
- #if 0
- case ('b'): /* force binary mode */
- if (negative)
- bflag = FALSE, negative = 0;
- else
- bflag = TRUE;
- break;
- #endif
- case ('c'):
- if (negative) {
- cflag = FALSE, negative = 0;
- #ifdef NATIVE
- aflag = FALSE;
- #endif
- } else {
- cflag = TRUE;
- #ifdef NATIVE
- aflag = TRUE; /* so you can read it on the screen */
- #endif
- }
- break;
- case ('d'): /* re-create directory structure (default) */
- if (negative)
- jflag = TRUE, negative = 0;
- break;
- case ('e'): /* just ignore -e, -x options (extract) */
- break;
- case ('f'): /* "freshen" (extract only newer files) */
- if (negative)
- fflag = uflag = FALSE, negative = 0;
- else
- fflag = uflag = TRUE;
- break;
- case ('j'): /* junk pathnames/directory structure */
- if (negative)
- jflag = FALSE, negative = 0;
- else
- jflag = TRUE;
- break;
- case ('l'):
- if (negative) {
- vflag = MAX(vflag-negative,0);
- negative = 0;
- } else
- ++vflag;
- break;
- case ('n'): /* don't overwrite any files */
- if (negative)
- overwrite_none = FALSE, negative = 0;
- else
- overwrite_none = TRUE;
- break;
- case ('o'): /* OK to overwrite files without prompting */
- if (negative) {
- overwrite_all = MAX(overwrite_all-negative,0);
- force_flag = MAX(force_flag-negative,0);
- negative = 0;
- } else {
- ++overwrite_all;
- ++force_flag; /* (share -o for now) force to cont. */
- }
- break;
- case ('p'): /* pipes: stdout, no tranlation, no messages */
- if (negative) {
- cflag = FALSE;
- quietflg = MAX(quietflg-999,0);
- negative = 0;
- } else {
- cflag = TRUE;
- quietflg += 999;
- }
- break;
- case ('q'): /* quiet: fewer comments/messages */
- if (negative) {
- quietflg = MAX(quietflg-negative,0);
- negative = 0;
- } else
- ++quietflg;
- break;
- #ifdef DOS_OS2
- case ('s'): /* spaces in filenames: allow by default */
- if (negative)
- sflag = TRUE, negative = 0;
- else
- sflag = FALSE;
- break;
- #endif
- case ('t'):
- if (negative)
- tflag = FALSE, negative = 0;
- else
- tflag = TRUE;
- break;
- case ('U'): /* Uppercase (don't convert to all-lower) */
- if (negative)
- U_flag = FALSE, negative = 0;
- else
- U_flag = TRUE;
- break;
- case ('u'): /* update (extract only new and newer files) */
- if (negative)
- uflag = FALSE, negative = 0;
- else
- uflag = TRUE;
- break;
- case ('V'): /* Version (retain VMS/DEC-20 file versions) */
- if (negative)
- V_flag = FALSE, negative = 0;
- else
- V_flag = TRUE;
- break;
- case ('v'): /* verbose */
- if (negative) {
- vflag = MAX(vflag-negative,0);
- negative = 0;
- } else if (vflag)
- ++vflag;
- else
- vflag = 2;
- break;
- #ifdef VMS
- case ('X'): /* restore owner/protection info (need privs?) */
- if (negative)
- secinf = FALSE, negative = 0;
- else
- secinf = TRUE;
- break;
- #endif /* VMS */
- case ('x'): /* extract: default */
- break;
- case ('z'): /* display only the archive comment */
- if (negative) {
- zflag -= negative;
- negative = 0;
- } else
- ++zflag;
- break;
- default:
- error = TRUE;
- break;
-
- } /* end switch */
- } /* end while (not end of argument string) */
- } /* end while (not done with switches) */
-
- /*---------------------------------------------------------------------------
- Make sure we aren't trying to do too many things here. [This seems like
- kind of a brute-force way to do things; but aside from that, isn't the
- -a option useful when listing the directory (i.e., for reading zipfile
- comments)? It's a modifier, not an action in and of itself, so perhaps
- it should not be included in the test--certainly, in the case of zipfile
- testing, it can just be ignored.]
- ---------------------------------------------------------------------------*/
-
- if ((aflag && tflag) || (aflag && vflag) || (cflag && tflag) ||
- (cflag && uflag) || (cflag && vflag) || (tflag && uflag) ||
- (tflag && vflag) || (uflag && vflag) || (fflag && overwrite_none)) {
- fprintf(stderr, "error:\
- -at, -av, -ct, -cu, -cv, -fn, -tu, -tv, -uv combinations not allowed\n");
- error = TRUE;
- }
- if (quietflg && (zflag > 0)) /* quietflg makes no sense */
- quietflg = 0;
- if (overwrite_all && overwrite_none) {
- fprintf(stderr, "caution: both -n and -o specified; ignoring -o\n");
- overwrite_all = FALSE;
- }
- if ((argc-- == 0) || error)
- RETURN(usage(error));
-
- /*---------------------------------------------------------------------------
- Now get the zipfile name from the command line and see if it exists as a
- regular (non-directory) file. If not, append the ".zip" suffix. We don't
- immediately check to see if this results in a good name, but we will do so
- later. In the meantime, see if there are any member filespecs on the com-
- mand line, and if so, set the filename pointer to point at them.
- ---------------------------------------------------------------------------*/
-
- strcpy(zipfn, *argv++);
- if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
- strcat(zipfn, ZSUFX);
- #ifdef UNIX /* no extension on Unix exe's--might find zip, not zip.zip; etc. */
- else if (statbuf.st_mode & S_IXUSR)
- fprintf(stderr, "note: file [ %s ] may be an executable\n\n", zipfn);
- #endif
-
- if (stat(zipfn, &statbuf)) { /* try again */
- fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn);
- RETURN(PK_NOZIP);
- } else
- ziplen = statbuf.st_size;
-
- filespecs = argc;
- xfilespecs = 0;
-
- if (argc != 0) {
- char **pp = argv-1;
- #ifdef DOS_OS2
- char *q;
-
- pfnames = argv;
- /* convert MSDOS-style directory separators to Unix-style ones */
- while (*pfnames != NULL) {
- for (q = *pfnames; *q; ++q)
- if (*q == '\\')
- *q = '/';
- ++pfnames;
- }
- #endif
- pfnames = argv;
- while (*++pp)
- if (!strcmp(*pp, "-x")) {
- if (pp > argv) {
- *pp = 0; /* terminate pfnames */
- filespecs = pp - pfnames;
- } else {
- pfnames = fnames; /* defaults */
- filespecs = 0;
- }
- pxnames = pp + 1; /* excluded-names ptr starts after -x */
- xfilespecs = argc - filespecs - 1;
- break; /* skip rest of args */
- }
- process_all_files = FALSE;
- } else
- process_all_files = TRUE; /* for speed */
-
- /*---------------------------------------------------------------------------
- Okey dokey, we have everything we need to get started. Let's roll.
- ---------------------------------------------------------------------------*/
-
- inbuf = (uch *)malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */
- outbuf = (uch *)malloc(OUTBUFSIZ + 1); /* 1 extra for string termin. */
- #ifndef DOS_OS2
- if (aflag) /* if need an ascebc scratch, */
- outout = (uch *)malloc(OUTBUFSIZ);
- else /* allocate it... */
- #endif /* !DOS_OS2 */
- outout = outbuf; /* else just point to outbuf */
-
- if ((inbuf == (uch *)NULL) || (outbuf == (uch *)NULL) ||
- (outout == (uch *)NULL)) {
- fprintf(stderr, "error: can't allocate unzip buffers\n");
- RETURN(PK_MEM);
- }
- hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */
-
- RETURN(process_zipfile()); /* keep passing errors back... */
-
- } /* end main() */
-
-
-
-
-
- /**********************/
- /* Function usage() */
- /**********************/
-
- int usage(error) /* return PK-type error code */
- int error;
- {
- #ifdef VMS
- # define QUOT '\"'
- # define EXAMPLE2 "vms.c"
- # define EXAMPLE1 \
- "unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS"
- #else
- # define QUOT ' '
- # define EXAMPLE2 "ReadMe"
- # define EXAMPLE1 \
- "unzip -p foo | more => send contents of foo.zip via pipe into program more"
- #endif
-
- #ifdef NATIVE
- #ifdef EBCDIC
- char *astring = "-a convert ASCII to EBCDIC";
- #else /* !EBCDIC */
- char *astring = "-a convert ASCII to native chars";
- #endif /* ?EBCDIC */
- /* char *astring = "-a convert ASCII to " NATIVE; (ANSI C concatenation) */
- char *loc_str = "";
- #else /* !NATIVE */
- #ifdef DOS_OS2
- char *astring = "-a convert text (LF => CR LF)";
- char *loc_str = " -s spaces in filenames => _";
- #else /* !DOS_OS2 */
- #ifdef MACOS
- char *astring = "-a convert text (CR LF => CR)";
- char *loc_str = "";
- #else /* !MACOS: UNIX, VMS, etc. */
- char *astring = "-a convert text (CR LF => LF)";
- #ifdef VMS
- char *loc_str = "\"-X\" restore owner/protection info";
- #else /* !VMS */
- char *loc_str = "";
- #endif /* ?VMS */
- #endif /* ?MACOS */
- #endif /* ?DOS_OS2 */
- #endif /* ?NATIVE */
- FILE *usagefp;
-
-
- /*---------------------------------------------------------------------------
- If user requested usage, send it to stdout; else send to stderr.
- ---------------------------------------------------------------------------*/
-
- if (error)
- usagefp = (FILE *)stderr;
- else
- usagefp = (FILE *)stdout;
-
- fprintf(usagefp, "\
- UnZip: Zipfile Extract %s; (c) 1989 S.H.Smith and others\n\
- Versions 3.0 and later by Info-ZIP. Bug reports ONLY to zip-bugs@cs.ucla.edu.\
- \n\n", VERSION);
-
- fprintf(usagefp, "\
- Usage: unzip [ -options[modifiers] ] file[.zip] [list] [-x xlist]\n\
- Default action is to extract all specified files except for those in xlist.\n\
- -c extract files to stdout/screen (CRT) -l list files (short format)\n\
- -p extract files to pipe, no messages -v list files (verbose format)\n\
- -f freshen existing files, create none -t test compressed archive data\n\
- -u update files, create if necessary -z display archive comment\n\
- -x exclude files which follow\n\
- modifiers:\n\
- -n never overwrite existing files %s\n", loc_str);
- fprintf(usagefp, "\
- -o overwrite files WITHOUT prompting %s\n\
- -j junk paths (don't make directories) %c-U%c don't make names lowercase\n\
- -q quiet mode (-qq => quieter) %c-V%c retain VMS version numbers\
- \n\n\
- Examples: (See unzip.doc for more information)\n\
- unzip data1 -x joe => extract all files except joe from zipfile data1.zip\n\
- %s\n\
- unzip -fo foo %-6s => quietly replace existing %s if archive file newer\n",
- astring, QUOT,QUOT, QUOT,QUOT, EXAMPLE1, EXAMPLE2,EXAMPLE2);
-
- if (error)
- return PK_PARAM;
- else
- return PK_COOL; /* just wanted usage screen: no error */
-
- } /* end function usage() */
-
- #endif /* ?MSWIN */
-
-
-
-
- /********************************/
- /* Function process_zipfile() */
- /********************************/
-
- int process_zipfile() /* return PK-type error code */
- {
- int error, error_in_archive;
-
-
- /*---------------------------------------------------------------------------
- Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
- lation, which would corrupt the bitstreams.
- ---------------------------------------------------------------------------*/
-
- #ifdef VMS
- if (check_format()) /* check for variable-length format */
- return PK_ERR;
- #endif /* VMS */
-
- if (open_input_file()) /* this should never happen, given the */
- return PK_NOZIP; /* stat() test in main(), but... */
-
- /*---------------------------------------------------------------------------
- Reconstruct the various PK signature strings, and find and process the
- end-of-central-directory header. Need only check last 65557 bytes of
- zipfile: comment may be up to 65535, end-of-central-directory record
- is 18 bytes, and signature itself is 4 bytes. Add some to allow for
- appended garbage.
- ---------------------------------------------------------------------------*/
-
- strcat(local_hdr_sig, LOCAL_HDR_SIG);
- strcat(central_hdr_sig, CENTRAL_HDR_SIG);
- strcat(end_central_sig, END_CENTRAL_SIG);
- /* strcat(extd_local_sig, EXTD_LOCAL_SIG); */
-
- if ((error_in_archive = find_end_central_dir(MIN(ziplen,66000L))) != 0 ||
- (error_in_archive = process_end_central_dir()) > PK_WARN) {
- close(zipfd);
- return error_in_archive;
- }
- if (zflag > 0) {
- close(zipfd);
- return error_in_archive;
- }
-
- /*---------------------------------------------------------------------------
- Test the end-of-central-directory info for incompatibilities and incon-
- sistencies.
- ---------------------------------------------------------------------------*/
-
- error = ((ecrec.number_this_disk == 1) &&
- (ecrec.num_disk_with_start_central_dir == 1));
-
- if ((ecrec.number_this_disk == 0) || error) {
- if (error) {
- fprintf(stderr,
- "\n Warning: zipfile claims to be disk 2 of a two-part archive;\n\
- attempting to process anyway. If no further errors occur, this\n\
- archive was probably created by PAK v2.51 or earlier. This bug\n\
- was reported to NoGate in March 1991 and was supposed to have been\n\
- fixed by mid-1991; as of mid-1992 it still hadn't been.\n\n");
- error_in_archive = PK_WARN;
- }
- if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) {
- fprintf(stderr, "\nerror: missing %ld bytes in zipfile (\
- attempting to process anyway)\n\n", -extra_bytes);
- error_in_archive = PK_ERR;
- } else if (extra_bytes > 0) {
- if ((ecrec.offset_start_central_directory == 0) &&
- (ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */
- {
- fprintf(stderr, "\nerror: NULL central directory offset (\
- attempting to process anyway)\n\n");
- ecrec.offset_start_central_directory = extra_bytes;
- extra_bytes = 0;
- error_in_archive = PK_ERR;
- } else {
- fprintf(stderr, "\nwarning: extra %ld bytes at beginning or\
- within zipfile\n (attempting to process anyway)\n\n", extra_bytes);
- error_in_archive = PK_WARN;
- }
- }
-
- /*-----------------------------------------------------------------------
- Check for empty zipfile and exit now if so.
- -----------------------------------------------------------------------*/
-
- if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0) {
- fprintf(stderr, "warning: zipfile is empty\n");
- close(zipfd);
- return (error_in_archive > PK_WARN)? error_in_archive : PK_WARN;
- }
-
- /*-----------------------------------------------------------------------
- Compensate for missing or extra bytes, and seek to where the start
- of central directory should be. If header not found, uncompensate
- and try again (necessary for at least some Atari archives created
- with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT 1.1).
- -----------------------------------------------------------------------*/
-
- LSEEK( ecrec.offset_start_central_directory )
- if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
- longint tmp = extra_bytes;
-
- extra_bytes = 0;
- LSEEK( ecrec.offset_start_central_directory )
- if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
- fprintf(stderr,
- "error: start of central directory not found; zipfile corrupt.\n");
- fprintf(stderr, ReportMsg);
- close(zipfd);
- return PK_BADERR;
- }
- fprintf(stderr, "error: reported length of central directory is \
- %d bytes too long\n (Atari STZIP zipfile? J.H.Holm ZIPSPLIT 1.1 \
- zipfile?).\n Compensating...\n\n", -tmp);
- error_in_archive = PK_ERR;
- }
-
- /*-----------------------------------------------------------------------
- Seek to the start of the central directory one last time, since we
- have just read the first entry's signature bytes; then list, extract
- or test member files as instructed, and close the zipfile.
- -----------------------------------------------------------------------*/
-
- LSEEK( ecrec.offset_start_central_directory )
- if (vflag)
- error = list_files(); /* LIST 'EM */
- else
- error = extract_or_test_files(); /* EXTRACT OR TEST 'EM */
- if (error > error_in_archive) /* don't overwrite stronger error */
- error_in_archive = error; /* with (for example) a warning */
- } else {
- fprintf(stderr, "\nerror: zipfile is part of multi-disk archive \
- (sorry, not supported).\n");
- error_in_archive = PK_FIND;
- }
-
- close(zipfd);
- return error_in_archive;
-
- } /* end function process_zipfile() */
-
-
-
-
-
- /**************************************/
- /* Function process_end_central_dir() */
- /**************************************/
-
- int process_end_central_dir() /* return PK-type error code */
- {
- int error = PK_COOL;
-
-
- /*---------------------------------------------------------------------------
- Get the zipfile comment (up to 64KB long), if any, and print it out.
- Then position the file pointer to the beginning of the central directory
- and fill buffer.
- ---------------------------------------------------------------------------*/
-
- #ifdef MSWIN
- cchComment = ecrec.zipfile_comment_length; /* save for comment button */
- if (ecrec.zipfile_comment_length && (zflag > 0)) {
- #else /* !MSWIN */
- if (ecrec.zipfile_comment_length && !(zflag < 0) && !quietflg) {
- if (zflag == 0)
- printf("[%s] comment:\n", zipfn);
- #endif /* ?MSWIN */
- if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
- fprintf(stderr, "\ncaution: zipfile comment truncated\n");
- error = PK_WARN;
- }
- }
- return error;
-
- } /* end function process_end_central_dir() */
-
-
-
-
-
- /* also referenced in UpdateListBox() in updatelb.c (Windows version) */
- char *Headers[][2] = {
- {" Length Date Time Name",
- " ------ ---- ---- ----"},
- {" Length Method Size Ratio Date Time CRC-32 Name",
- " ------ ------ ---- ----- ---- ---- ------ ----"}
- };
-
- /*************************/
- /* Function list_files() */
- /*************************/
-
- int list_files() /* return PK-type error code */
- {
- int do_this_file=FALSE, ratio, error, error_in_archive=PK_COOL;
- int which_hdr=(vflag>1), date_format;
- ush j, yr, mo, dy, hh, mm, members=0;
- ulg tot_csize=0L, tot_ucsize=0L;
- #ifdef OS2
- ulg tot_easize=0L, tot_eafiles=0L, ea_size;
- #endif
- #ifdef MSWIN
- PSTR psLBEntry; /* list box entry */
- #endif
- min_info info;
- static char *method[NUM_METHODS+1] =
- {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
- "Implode", "Token", "Deflate", unkn};
-
-
-
- /*---------------------------------------------------------------------------
- Unlike extract_or_test_files(), this routine confines itself to the cen-
- tral directory. Thus its structure is somewhat simpler, since we can do
- just a single loop through the entire directory, listing files as we go.
-
- So to start off, print the heading line and then begin main loop through
- the central directory. The results will look vaguely like the following:
-
- Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case
- ------ ------ ---- ----- ---- ---- ------ ---- conversion)
- 44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX
- 3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext
- ---------------------------------------------------------------------------*/
-
- pInfo = &info;
- date_format = dateformat();
-
- #ifndef MSWIN
- if (quietflg < 2)
- if (U_flag)
- printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
- else
- printf("%s (\"^\" ==> case\n%s conversion)\n",
- Headers[which_hdr][0], Headers[which_hdr][1]);
- #endif /* !MSWIN */
-
- for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
-
- if (readbuf(sig, 4) <= 0)
- return PK_EOF;
- if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */
- fprintf(stderr, CentSigMsg, j); /* sig not found */
- fprintf(stderr, ReportMsg); /* check binary transfers */
- return PK_BADERR;
- }
- /* process_cdir_file_hdr() sets pInfo->lcflag: */
- if ((error = process_cdir_file_hdr()) != PK_COOL)
- return error; /* only PK_EOF defined */
-
- /*
- * We could DISPLAY the filename instead of storing (and possibly trun-
- * cating, in the case of a very long name) and printing it, but that
- * has the disadvantage of not allowing case conversion--and it's nice
- * to be able to see in the listing precisely how you have to type each
- * filename in order for unzip to consider it a match. Speaking of
- * which, if member names were specified on the command line, check in
- * with match() to see if the current file is one of them, and make a
- * note of it if it is.
- */
-
- if ((error = do_string(crec.filename_length, FILENAME)) != PK_COOL) {
- error_in_archive = error; /* ^--(uses pInfo->lcflag) */
- if (error > PK_WARN) /* fatal: can't continue */
- return error;
- }
- if (extra_field != (uch *)NULL)
- free(extra_field);
- extra_field = (uch *)NULL;
- if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) {
- error_in_archive = error;
- if (error > PK_WARN) /* fatal */
- return error;
- }
- if (!process_all_files) { /* check if specified on command line */
- char **pfn = pfnames-1;
-
- do_this_file = FALSE;
- while (*++pfn)
- if (match(filename, *pfn)) {
- do_this_file = TRUE;
- break; /* found match, so stop looping */
- }
- if (do_this_file) { /* check if this is an excluded file */
- char **pxn = pxnames-1;
-
- while (*++pxn)
- if (match(filename, *pxn)) {
- do_this_file = FALSE;
- break;
- }
- }
- }
- /*
- * If current file was specified on command line, or if no names were
- * specified, do the listing for this file. Otherwise, get rid of the
- * file comment and go back for the next file.
- */
-
- if (process_all_files || do_this_file) {
-
- yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % (unsigned)100;
- mo = (crec.last_mod_file_date >> 5) & 0x0f;
- dy = crec.last_mod_file_date & 0x1f;
-
- /* twist date so it displays according to national convention */
- switch (date_format) {
- case DF_YMD:
- hh = mo; mo = yr; yr = dy; dy = hh; break;
- case DF_DMY:
- hh = mo; mo = dy; dy = hh;
- }
- hh = (crec.last_mod_file_time >> 11) & 0x1f;
- mm = (crec.last_mod_file_time >> 5) & 0x3f;
-
- csize = (longint) crec.csize;
- ucsize = (longint) crec.ucsize;
- if (crec.general_purpose_bit_flag & 1)
- csize -= 12; /* if encrypted, don't count encrypt hdr */
-
- ratio = (ucsize == 0) ? 0 : /* .zip can have 0-length members */
- ((ucsize > 2000000L) ? /* risk signed overflow if mult. */
- (int) ((ucsize-csize) / (ucsize/1000L)) + 5 : /* big */
- (int) ((1000L*(ucsize-csize)) / ucsize) + 5); /* small */
-
- #if 0 /* GRR/Euro: add this? define p above */
- #if defined(DOS_OS2) || defined(UNIX)
- for (p = filename; *p; ++p)
- if (!isprint(*p))
- *p = '?'; /* change non-printable chars to '?' */
- #endif /* DOS_OS2 || UNIX */
- #endif /* 0 */
-
- #ifdef MSWIN
- #ifdef NEED_EARLY_REDRAW
- /* turn on listbox redrawing just before adding last line */
- if (j == (ecrec.total_entries_central_dir-1))
- (void)SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);
- #endif /* NEED_EARLY_REDRAW */
- psLBEntry =
- (PSTR)LocalAlloc(LMEM_FIXED, FILNAMSIZ+LONG_FORM_FNAME_INX);
- switch (which_hdr) {
- case 0: /* short form */
- OemToAnsi(filename, filename); /* translate to ANSI */
- wsprintf(psLBEntry, "%7ld %02u-%02u-%02u %02u:%02u %c%s",
- (long)ucsize, mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '),
- (LPSTR)filename);
- SendMessage(hWndList, LB_ADDSTRING, 0,
- (LONG)(LPSTR)psLBEntry);
- break;
- case 1: /* verbose */
- OemToAnsi(filename, filename); /* translate to ANSI */
- wsprintf(psLBEntry,
- "%7ld %-7s%7ld %3d%% %02u-%02u-%02u %02u:%02u %08lx %c%s",
- (long)ucsize, (LPSTR)method[methnum], (long)csize,
- ratio/10, mo, dy, yr, hh, mm, (unsigned long)crec.crc32,
- (pInfo->lcflag?'^':' '), (LPSTR)filename);
- SendMessage(hWndList, LB_ADDSTRING, 0,
- (LONG)(LPSTR)psLBEntry);
- }
- LocalFree((HANDLE)psLBEntry);
- #else /* !MSWIN */
- if (which_hdr == 0) /* short form */
- printf("%7ld %02u-%02u-%02u %02u:%02u %c%s\n", ucsize,
- mo, dy, yr, hh, mm, (pInfo->lcflag?'^':' '), filename);
- else /* verbose */
- printf(
- "%7ld %-7s%7ld %3d%% %02u-%02u-%02u %02u:%02u %08lx %c%s\n",
- ucsize, method[methnum], csize, ratio/10, mo, dy, yr,
- hh, mm, crec.crc32, (pInfo->lcflag?'^':' '), filename);
- #endif /* ?MSWIN */
-
- error = do_string(crec.file_comment_length, QCOND? DISPLAY : SKIP);
- if (error) {
- error_in_archive = error; /* might be just warning */
- if (error > PK_WARN) /* fatal */
- return error;
- }
- tot_ucsize += (ulg)ucsize;
- tot_csize += (ulg)csize;
- ++members;
- #ifdef OS2
- if ((ea_size = SizeOfEAs(extra_field)) != 0) {
- tot_easize += ea_size;
- tot_eafiles++;
- }
- #endif
- } else { /* not listing this file */
- SKIP_(crec.file_comment_length)
- }
- } /* end for-loop (j: files in central directory) */
-
- /*---------------------------------------------------------------------------
- Print footer line and totals (compressed size, uncompressed size, number
- of members in zipfile).
- ---------------------------------------------------------------------------*/
-
- ratio = (tot_ucsize == 0) ?
- 0 : ((tot_ucsize > 4000000L) ? /* risk unsigned overflow if mult. */
- (int)((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 :
- (int)((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5 );
-
- if (quietflg < 2) {
- #ifdef MSWIN
- /* Display just the totals since the dashed lines get displayed
- * in UpdateListBox(). Get just enough space to display total. */
- if (which_hdr) /* verbose */
- wsprintf(lpumb->szTotalsLine,
- "%7lu %7lu %3d%% %-7u",
- (ulg)tot_ucsize, (ulg)tot_csize, ratio/10, members);
- else /* short */
- wsprintf(lpumb->szTotalsLine, "%7lu %-7u",
- (ulg)tot_ucsize, members);
- #else /* !MSWIN */
- if (which_hdr) /* verbose */
- printf(" ------ ------ --- \
- -------\n%7lu %7lu %3d%% \
- %-7u\n", tot_ucsize, tot_csize, ratio/10, members);
- else /* short */
- printf(" ------ -------%s\n%7lu \
- %-7u\n", tot_ucsize, members);
- #endif /* ?MSWIN */
- #ifdef OS2
- if (tot_eafiles && tot_easize)
- printf("\n%ld file%s %ld bytes of EA's attached.\n", tot_eafiles,
- tot_eafiles == 1 ? " has" : "s have a total of", tot_easize);
- #endif
- }
- /*---------------------------------------------------------------------------
- Double check that we're back at the end-of-central-directory record.
- ---------------------------------------------------------------------------*/
-
- readbuf(sig, 4);
- if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */
- fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */
- error_in_archive = PK_WARN;
- }
- return error_in_archive;
-
- } /* end function list_files() */
-
-
-
-
-
- /**************************************/
- /* Function process_cdir_file_hdr() */
- /**************************************/
-
- int process_cdir_file_hdr() /* return PK-type error code */
- {
- int error;
-
-
- /*---------------------------------------------------------------------------
- Get central directory info, save host and method numbers, and set flag
- for lowercase conversion of filename, depending on the OS from which the
- file is coming.
- ---------------------------------------------------------------------------*/
-
- if ((error = get_cdir_file_hdr()) != 0)
- return error;
-
- pInfo->hostnum = MIN(crec.version_made_by[1], NUM_HOSTS);
- /* extnum = MIN(crec.version_needed_to_extract[1], NUM_HOSTS); */
- methnum = MIN(crec.compression_method, NUM_METHODS);
- if (methnum == NUM_METHODS)
- sprintf(unkn, "Unk:%03d", crec.compression_method);
-
- pInfo->lcflag = 0;
- if (!U_flag) /* as long as user hasn't specified case-preservation */
- switch (pInfo->hostnum) {
- case FS_FAT_: /* PKZIP and zip -k store in uppercase */
- case VM_CMS_: /* all caps? */
- case CPM_: /* like DOS, right? */
- /* case ATARI_: ? */
- /* case Z_SYSTEM_: ? */
- case TOPS20_:
- /* case QDOS_: ? */
- pInfo->lcflag = 1; /* convert filename to lowercase */
- break;
-
- /* case VMS_: VMS Zip converts filenames to lowercase */
- default: /* AMIGA_, UNIX_, (ATARI_), FS_HPFS_, MAC_, */
- break; /* (Z_SYSTEM_), FS_NTFS_: no conversion */
- }
-
- return PK_COOL;
-
- } /* end function process_cdir_file_hdr() */
-
-
-
-
-
- /***************************************/
- /* Function process_local_file_hdr() */
- /***************************************/
-
- int process_local_file_hdr() /* return PK-type error code */
- {
- local_byte_hdr byterec;
-
-
- /*---------------------------------------------------------------------------
- Read the next local file header and do any necessary machine-type con-
- versions (byte ordering, structure padding compensation--do so by copy-
- ing the data from the array into which it was read (byterec) to the
- usable struct (lrec)).
- ---------------------------------------------------------------------------*/
-
- if (readbuf((char *)byterec, LREC_SIZE) <= 0)
- return PK_EOF;
-
- lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
- lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
-
- lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
- lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
- lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
- lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
- lrec.crc32 = makelong(&byterec[L_CRC32]);
- lrec.csize = makelong(&byterec[L_COMPRESSED_SIZE]);
- lrec.ucsize = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
- lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
- lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
-
- csize = (longint) lrec.csize;
- ucsize = (longint) lrec.ucsize;
-
- if ((lrec.general_purpose_bit_flag & 8) != 0) {
- /* can't trust local header, use central directory: */
- lrec.crc32 = pInfo->crc;
- csize = (longint)(lrec.csize = pInfo->compr_size);
- }
-
- return PK_COOL;
-
- } /* end function process_local_file_hdr() */
-